#include "qscibasiclexer.h"
#include "Qsci/qsciscintilla.h"
#include <QRegularExpression>
#include <QVector>

QStringList
    blue_tokens{"var", "del", "func", "end", "and", "not", "or", "null", "true", "false", "M_PI"};

QStringList yellow_tokens{"(", ")", "{", "}"};

QStringList purple_tokens{"if",
                          "else",
                          "elif",
                          "for",
                          "while",
                          "then",
                          "to",
                          "step",
                          "return",
                          "break",
                          "continue",
                          "[",
                          "]"};

// aka functions
QStringList dim_yellow_tokens{"run",
                              "print",
                              "prints",
                              "print_ret",
                              "input",
                              "input_num",
                              "clear",
                              "is_num",
                              "is_str",
                              "is_list",
                              "is_func",
                              "len",
                              "append",
                              "pop",
                              "pop_back",
                              "pop_front",
                              "extend",
                              "swap"};

QsciBasicLexer::QsciBasicLexer(QObject *parent) : QsciLexerCustom(parent)
{
    // Default text color
    setDefaultColor(QColor(0, 0, 0));       // 黑字
    setDefaultPaper(QColor(255, 255, 255)); // 白底
    setDefaultFont(QFont("Consolas", 16));  // 16号

    // Init color per style
    setColor(QColor(0, 0, 0), 0);   // 黑色(Black)
    setColor(QColor(187, 104, 214), 1); // 紫色(Purple)
    setColor(QColor(53, 140, 214), 2);  // 蓝(Blue)
    setColor(QColor(106, 153, 85), 3);  // 绿色(Green)
    setColor(QColor(255, 215, 0), 4);   // 黄色(Yellow)
    setColor(QColor(216, 192, 109), 5); // 暗黄色(DimYellow)

    // Init paper color & fonts per style
    for (size_t i = 0; i <= 5; i++) {
        setPaper(QColor(255, 255, 255), i);             // 白色(White)
        setFont(QFont("Consolas", 16, QFont::Bold), i); // 16pt bold
    }
}

const char *QsciBasicLexer::language() const
{
    return "Basic";
}

QString QsciBasicLexer::description(int style) const
{
    switch (style) {
    case 0:
        return QString("default");
    case 1:
        return QString("purple");
    case 2:
        return QString("blue");
    case 3:
        return QString("green");
    case 4:
        return QString("cyan");
    case 5:
        return QString("yellow");
    case 6:
        return QString("light_yellow");
    }
    return QString();
}

void QsciBasicLexer::styleText(int start, int end)
{
    // 1. Initialize styling
    startStyling(start);

    // 2. Slice out part from text
    QsciScintilla *attached_editor = this->editor();
    QString sub_text = attached_editor->text().mid(start, end - start);

    // 3. Tokenize the text
    QRegularExpression re("\\s+|\\w+|\\W");
    QRegularExpressionMatchIterator i = re.globalMatch(sub_text);

    // 4. Style the text
    bool notation = false;
    while (i.hasNext()) {
        QRegularExpressionMatch match = i.next();
        if (match.hasMatch()) {
            QString token = match.captured();
            if (notation) {
                if (token == "\n" || token == "\r\n")
                    notation = false;
                else
                    setStyling(token.length(), 3);
            } else {
                if (purple_tokens.contains(token))
                    setStyling(token.length(), 1);
                else if (blue_tokens.contains(token))
                    setStyling(token.length(), 2);
                else if (token == "#") {
                    setStyling(token.length(), 3);
                    notation = true;
                } else if (yellow_tokens.contains(token))
                    setStyling(token.length(), 4);
                else if (dim_yellow_tokens.contains(token))
                    setStyling(token.length(), 5);
                else
                    setStyling(token.length(), 0);
            }
        }
    }
}
